/*
 * The contents of this web application are subject to the Mozilla Public License Version 
 * 1.1 (the "License"); you may not use this web application except in compliance with 
 * the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/.
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, 
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License 
 * for the specific language governing rights and limitations under the License.
 * 
 * The Original Code is owned by and the Initial Developer of the Original Code is 
 * Composite A/S (Danish business reg.no. 21744409). All Rights Reserved
 * 
 * Section 11 of the License is EXPRESSLY amended to include a provision stating 
 * that any dispute, including but not limited to disputes related to the enforcement 
 * of the License, to which Composite A/S as owner of the Original Code, as Initial 
 * Developer or in any other role, becomes a part to shall be governed by Danish law 
 * and be initiated before the Copenhagen City Court ("K�benhavns Byret")            
 */

//===============================================================================
// Microsoft patterns & practices Enterprise Library
// Core
//===============================================================================
// Copyright © Microsoft Corporation.  All rights reserved.
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY
// OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT
// LIMITED TO THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
// FITNESS FOR A PARTICULAR PURPOSE.
//===============================================================================

using System.Collections.Generic;


namespace Composite.Core.Configuration
{
    /// <summary>
    /// This should be a part of the I/O layer
    /// </summary>
    internal class FileConfigurationSourceImplementation : Microsoft.Practices.EnterpriseLibrary.Common.Configuration.BaseFileConfigurationSourceImplementation
    {
        private string configurationFilepath;
        private System.Configuration.ExeConfigurationFileMap fileMap;
        private System.Configuration.Configuration cachedConfiguration;
        private object cachedConfigurationLock = new object();



        public FileConfigurationSourceImplementation(string configurationFilepath)
            : this(configurationFilepath, true)
        {
        }

       

        public FileConfigurationSourceImplementation(string configurationFilepath, bool refresh)
            : base(configurationFilepath, refresh)
        {
            this.configurationFilepath = configurationFilepath;
            this.fileMap = new System.Configuration.ExeConfigurationFileMap();
            fileMap.ExeConfigFilename = configurationFilepath;
        }



        [System.Diagnostics.CodeAnalysis.SuppressMessage("Composite.IO", "Composite.DoNotUseConfigurationClass:DoNotUseConfigurationClass", Justification = "The implementation may use it")]
        public override System.Configuration.ConfigurationSection GetSection(string sectionName)
        {
            System.Configuration.Configuration configuration = GetConfiguration();

            System.Configuration.ConfigurationSection configurationSection = configuration.GetSection(sectionName) as System.Configuration.ConfigurationSection;

            SetConfigurationWatchers(sectionName, configurationSection);

            return configurationSection;
        }



        [System.Diagnostics.CodeAnalysis.SuppressMessage("Composite.IO", "Composite.DoNotUseConfigurationClass:DoNotUseConfigurationClass", Justification = "The implementation may use it")]
        protected override void RefreshAndValidateSections(IDictionary<string, string> localSectionsToRefresh, IDictionary<string, string> externalSectionsToRefresh, out ICollection<string> sectionsToNotify, out IDictionary<string, string> sectionsWithChangedConfigSource)
        {
            UpdateCache();

            sectionsToNotify = new List<string>();
            sectionsWithChangedConfigSource = new Dictionary<string, string>();

            // refresh local sections and determine what to do.
            foreach (KeyValuePair<string, string> sectionMapping in localSectionsToRefresh)
            {
                System.Configuration.ConfigurationSection section = cachedConfiguration.GetSection(sectionMapping.Key) as System.Configuration.ConfigurationSection;
                string refreshedConfigSource = section != null ? section.SectionInformation.ConfigSource : NullConfigSource;
                if (!sectionMapping.Value.Equals(refreshedConfigSource))
                {
                    sectionsWithChangedConfigSource.Add(sectionMapping.Key, refreshedConfigSource);
                }

                // notify anyway, since it might have been updated.
                sectionsToNotify.Add(sectionMapping.Key);
            }

            // refresh external sections and determine what to do.
            foreach (KeyValuePair<string, string> sectionMapping in externalSectionsToRefresh)
            {
                System.Configuration.ConfigurationSection section = cachedConfiguration.GetSection(sectionMapping.Key) as System.Configuration.ConfigurationSection;
                string refreshedConfigSource = section != null ? section.SectionInformation.ConfigSource : NullConfigSource;
                if (!sectionMapping.Value.Equals(refreshedConfigSource))
                {
                    sectionsWithChangedConfigSource.Add(sectionMapping.Key, refreshedConfigSource);

                    // notify only if che config source changed
                    sectionsToNotify.Add(sectionMapping.Key);
                }
            }
        }

        

        protected override void RefreshExternalSections(string[] sectionsToRefresh)
        {
            UpdateCache();
        }




        [System.Diagnostics.CodeAnalysis.SuppressMessage("Composite.IO", "Composite.DoNotUseConfigurationManagerClass:DoNotUseConfigurationManagerClass", Justification = "The implementation may use it")]
        private System.Configuration.Configuration GetConfiguration()
        {
            if (cachedConfiguration == null)
            {
                lock (cachedConfigurationLock)
                {
                    if (cachedConfiguration == null)
                    {
                        cachedConfiguration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, System.Configuration.ConfigurationUserLevel.None);
                    }
                }
            }

            return cachedConfiguration;
        }



        [System.Diagnostics.CodeAnalysis.SuppressMessage("Composite.IO", "Composite.DoNotUseConfigurationManagerClass:DoNotUseConfigurationManagerClass", Justification = "The implementation may use it")]
        internal void UpdateCache()
        {
            System.Configuration.Configuration newConfiguration
                = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(fileMap, System.Configuration.ConfigurationUserLevel.None);
            lock (cachedConfigurationLock)
            {
                cachedConfiguration = newConfiguration;
            }
        }
    }
}
